/* State.cpp
Michael Zahniser, 12/12/09

Function definitions for the State class.
*/

#include "State.h"

using std::string;
using std::vector;
using std::map;



State::State()
{
	Reset();
}



// Clear the stack.
void State::Clear()
{
	stack.clear();
	function.clear();
	
	mode = CALCULATING;
}



// Reset the state entirely (clear all variables and functions).
void State::Reset()
{
	Clear();
	
	variables.clear();
	functions.clear();
	
	base = 10;
	angle = DEGREES;
}



// Determine the current operating mode.
State::EntryMode State::Mode() const
{
	return mode;
}



void State::SetMode(EntryMode mode)
{
	this->mode = mode;
}



// Determine the current base.
int State::Base() const
{
	return base;
}



void State::SetBase(int base)
{
	this->base = base;
}



// Toggle between degrees and radians.
State::AngleMode State::Angle() const
{
	return angle;
}



void State::SetAngle(AngleMode angle)
{
	this->angle = angle;
}



const vector<double> State::Stack() const
{
	return stack;
}



const vector<string> State::Function() const
{
	return function;
}



// Access the stack of values.
double State::Pop()
{
	if(stack.empty())
		throw string("not enough args");
	double value = stack.back();
	stack.pop_back();
	return value;
}



long long State::PopInt()
{
	return static_cast<long long>(Pop() + .5);
}



void State::Push(double value)
{
	stack.push_back(value);
}



// Add a word, uninterpreted.
// If functionming, it gets added onto the function.
// If defining, the word is used as the variable or function name.
void State::Push(const string &word)
{
	if(mode == PROGRAMMING)
	{
		if(word == "call" || word == "}")
		{
			if(function.empty())
				function.push_back("");
			mode = DEFINING;
		}
		else
			function.push_back(word);
	}
	else
	{
		if(mode == DEFINING)
		{
			if(function.empty())
				variables[word] = Pop();
			else
			{
				if(function[0].empty())
					functions[word].clear();
				else
					functions[word] = function;
				function.clear();
			}
		}
		mode = CALCULATING;
	}
}



// Check if the given word is a variable.
bool State::HasVariable(const string &word)
{
	return (variables.find(word) != variables.end());
}



double State::Variable(const string &word)
{
	map<string, double>::const_iterator it = variables.find(word);
	if(it == variables.end())
		throw string("bad variable name");
	return it->second;
}



// Check if the given word is a function.
bool State::HasFunction(const string &word)
{
	return (functions.find(word) != functions.end());
}



const vector<string> &State::Function(const string &word)
{
	map<string, vector<string> >::const_iterator it = functions.find(word);
	if(it == functions.end())
		throw string("bad function name");
	return it->second;
}
